﻿using System;
using System.CodeDom.Compiler;
using System.IO;
using ODataValidator.RuleEngine;

namespace CodeRuleBuilder
{
    class SimpleResultConsumer : IResultProvider, ILogger
    {
        public void Accept(TestResult result)
        {
            Console.WriteLine("{0}:{1}:{2}:{3}",
                result.RuleName,
                result.Classification,
                result.ErrorDetail,
                result.Description
                );
        }

        public void JobCompleted(bool errorOccurred)
        {                  
        }

        public void Log(RuntimeException runtimeError)
        {
        }
    }

    class Program
    {
        static void DeleteFiles()
        {
            string[] fileList = Directory.GetFiles(Path.Combine(System.Environment.CurrentDirectory, @"extensions") , "*.*");

            foreach (string file in fileList)
            {
                File.Delete(file);
            }
        }

        static bool CompileClassLibrary(String sourceName)
        {
            DeleteFiles();
            FileInfo sourceFile = new FileInfo(sourceName);
            CodeDomProvider provider = null;
            bool compileOk = false;

            provider = CodeDomProvider.CreateProvider("CSharp");

            if (provider != null)
            {
                String dllName = String.Format(@"{0}\extensions\{1}.dll", System.Environment.CurrentDirectory, sourceFile.Name.Substring(0, sourceFile.Name.IndexOf(".")));
                CompilerParameters cp = new CompilerParameters();

                // Depending on the rule, add / remove references accordingly
                cp.ReferencedAssemblies.Add("System.dll");
                cp.ReferencedAssemblies.Add("System.ComponentModel.Composition.dll");
                cp.ReferencedAssemblies.Add("System.Core.dll");
                cp.ReferencedAssemblies.Add("System.Net.dll");
                cp.ReferencedAssemblies.Add("System.Web.dll");
                cp.ReferencedAssemblies.Add("System.Xml.dll");
                cp.ReferencedAssemblies.Add("Commons.Xml.Relaxng.dll");
                cp.ReferencedAssemblies.Add("Newtonsoft.Json.Net35.dll");
                cp.ReferencedAssemblies.Add("ODataValidator.RuleEngine.dll");
                cp.ReferencedAssemblies.Add("System.Xml.Linq.dll");
                cp.ReferencedAssemblies.Add("ODataValidator.CodeRules.dll");

                cp.GenerateExecutable = false;
                cp.OutputAssembly = dllName;
                cp.GenerateInMemory = false;
                cp.TreatWarningsAsErrors = false;
                cp.IncludeDebugInformation = true;

                CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourceName);

                if (cr.Errors.Count > 0)
                {
                    Console.WriteLine("Errors building {0} into {1}", sourceName, cr.PathToAssembly);
                    foreach (CompilerError ce in cr.Errors)
                    {
                        Console.WriteLine("  {0}", ce.ToString());
                        Console.WriteLine();
                    }
                }
                else
                {
                    Console.WriteLine("Source {0} built into {1} successfully.", sourceName, cr.PathToAssembly);
                }

                if (cr.Errors.Count > 0)
                {
                    compileOk = false;
                }
                else
                {
                    compileOk = true;
                }
            }

            return compileOk;
        }

        static class Format
        {
            public const string AtomPub = "atompub";
            public const string Json = "json";
        }

        static class RuleFile
        {
            static class RuleCategory
            {
                public const string Common = "Common";
                public const string MetadataDocument = "MetadataDocument";
                public const string ServiceDocument = "ServiceDocument";
                public const string Feed = "Feed";
                public const string Entry = "Entry";
                public const string Property = "Property";
                public const string Link = "Link";
                public const string Value = "Value";
            }

            // Specify the rule category and rule name
            public const string Path = @"..\..\..\..\src\CodeRules\";            
            public const string Category = RuleCategory.Entry;
            public const string Name = "EntryCore2024.cs";
        }

        static void Main(string[] args)
        {
            // Code rule file path and name
            string[] filePaths = Directory.GetFiles(Path.Combine(RuleFile.Path, RuleFile.Category), RuleFile.Name);

            bool isCompiled = CompileClassLibrary(filePaths[0]);
            Console.WriteLine();

            if (isCompiled)
            {
                // Targeted Uri - SvcDoc, Metadata, Feed, Entry, Property, Link, or Value
                string destination = "http://odata.netflix.com/v2/Catalog/Titles('13aly')";

                // Format = AtomPub | Json
                string format = Format.Json;

                var logger = new SimpleResultConsumer();

                var store = new ExtensionRuleStore("extensions", logger);
                foreach (var rule in store.GetRules())
                {
                    if (rule.IsValid())
                    {
                        RuleCatalogCollection.Instance.Add(rule);
                    }
                }

                Guid jobId = Guid.NewGuid();
                var context = ServiceContextFactory.Create(destination, format, jobId, 1024 * 1024);

                var facade = new RuleEngineWrapper(context, logger, logger);
                facade.Validate();
            }

            Console.ReadKey();
        }
    }
}

